package com.dlc.shop.service.impl;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.format.FastDateFormat;
import cn.hutool.core.util.StrUtil;
import com.dlc.shop.common.bean.leaf.Result;
import com.dlc.shop.common.bean.leaf.Status;
import com.dlc.shop.common.exception.leaf.InitException;
import com.dlc.shop.common.exception.leaf.LeafServerException;
import com.dlc.shop.common.exception.leaf.NoKeyException;
import com.dlc.shop.service.IDAllocDao;
import com.dlc.shop.service.IDGen;
import com.dlc.shop.service.SegmentService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.util.Date;
import java.util.Objects;

/**
 * @author left
 */
@Service("SegmentService")
public class SegmentServiceImpl implements SegmentService {

    private static final Logger logger = LoggerFactory.getLogger(SegmentServiceImpl.class);

    /**
     * 标准日期时间格式，精确到秒：yyyy-MM-dd HH:mm:ss
     */
    public static final String DATETIME_PATTERN = "yyMMdd";

    public static final FastDateFormat DATETIME_FORMAT = FastDateFormat.getInstance(DATETIME_PATTERN);

    private final IDGen idGen;

    /**
     * 日期长度
     */
    public static final int DATE_LENGTH = 6;

    /**
     * id默认长度
     */
    public static final int ID_DEFAULT_LENGTH = 15;

    /**
     * 日期id的长度为16
     */
    public static final int ID_DATE_LENGTH = 16;

    @Value("${application.workerId:}")
    private String workerId;

    public SegmentServiceImpl(DataSource dataSource) throws InitException {
        // Config Dao
        IDAllocDao dao = new IDAllocDaoImpl(dataSource);

        // Config ID Gen
        idGen = new SegmentIDGenImpl();
        ((SegmentIDGenImpl) idGen).setDao(dao);
        if (idGen.init()) {
            logger.info("Segment Service Init Successfully");
        } else {
            throw new InitException("Segment Service Init Fail");
        }

    }

    @Override
    public Long getSegmentId(String key) {
        // 默认我们给个15位
        return genNo(key, ID_DEFAULT_LENGTH);
    }

    @Override
    public Long getSegmentId(String key, Integer len) {
        return genNo(key, len);
    }


    @Override
    public String getSegmentCode(String key, Integer length) {
        return genNoStr(key, length);
    }


    @Override
    public Long getDateFormatSegmentId(String key) {
        // 默认生成转换为16位长度的id，js long的精度是16位的，所以默认我们也给个16位 6 + 7 + 最后3位是userId这很关键
        // 这里的7位id其中有x位用来区分测试环境和生产环境，还有7-x位用来生成id，如果是全局id，7-（x+1）位
        // 所以workerId最好是一位数，或者没有
        String id = getDateTime() + genNoStr(key, ID_DATE_LENGTH - DATE_LENGTH);
        return Long.valueOf(id);
    }


    private Long genNo(String key, int length){
        Long nextId = get(key, length);
        if (StrUtil.isBlank(workerId)) {
            return nextId;
        }
        return Long.parseLong(workerId + nextId);
    }

    /**
     * 填充0，使id达到指定长度的字符串
     * @param key
     * @param length
     * @return
     */
    private String genNoStr(String key, int length){
        Long nextId = get(key, length);
        // 在id前面补零， length为补零后的长度， d:表示为正数类型
        length = length - workerId.length();
        String newId = String.format("%0" + length + "d", nextId);
        return workerId + newId;
    }

    private Long get(String key, Integer length) {
        // length - x 是为了留位置出来补足workId
        length = length - workerId.length();
        Result result;
        if (key == null || key.isEmpty()) {
            throw new NoKeyException();
        }
        Result id = getId(key, length);
        result = id;
        if (Objects.equals(result.getStatus(), Status.EXCEPTION)) {
            throw new LeafServerException(result.toString());
        }
        return result.getId();
    }

    public Result getId(String key, int length) {
        return idGen.get(key, length);
    }

    public SegmentIDGenImpl getIdGen() {
        if (idGen instanceof SegmentIDGenImpl) {
            return (SegmentIDGenImpl) idGen;
        }
        return null;
    }

    private String getDateTime() {
        return DateUtil.format(new Date(), DATETIME_FORMAT);
    }

}
